package com.qingyun.web.security.provider;


import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.qingyun.common.constant.Constants;
import com.qingyun.common.core.domain.model.LoginUser;
import com.qingyun.common.core.redis.RedisCache;
import com.qingyun.common.enums.SysUserType;
import com.qingyun.common.exception.user.CaptchaExpireException;
import com.qingyun.common.utils.MessageUtils;
import com.qingyun.common.utils.ServletUtils;
import com.qingyun.framework.web.service.AsyncService;
import com.qingyun.security.enums.App;
import com.qingyun.security.exception.AuthoException;
import com.qingyun.security.exception.CaptchaAuthoException;
import com.qingyun.security.provider.AbstractUserDetailsAuthenticationProvider;
import com.qingyun.security.utils.SecurityUtils;
import com.qingyun.shop.domain.TiktokProxy;
import com.qingyun.shop.domain.TiktokUserProxy;
import com.qingyun.shop.domain.TiktokUserShop;
import com.qingyun.shop.mapper.TiktokUserProxyMapper;
import com.qingyun.shop.mapper.TiktokUserShopMapper;
import com.qingyun.shop.service.ITiktokProxyService;
import com.qingyun.shop.service.ITiktokShopService;
import com.qingyun.system.service.ISysConfigService;
import com.qingyun.web.security.service.UserDetailsServiceImpl;
import com.qingyun.web.security.token.AdminAuthenticationToken;
import lombok.AllArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.stereotype.Component;

/**
 * @author dangyonghang
 */
@Component
@AllArgsConstructor
@Slf4j
public class SystemAdminAuthenticationProvider extends AbstractUserDetailsAuthenticationProvider {

    private RedisCache redisCache;

    private UserDetailsServiceImpl userDetailsService;

   private PasswordEncoder passwordEncoder;

   private AsyncService asyncService;

	private ISysConfigService configService;

	private ITiktokShopService tiktokShopService;

	private ITiktokProxyService tiktokProxyService;

	private TiktokUserShopMapper userShopMapper;

	private TiktokUserProxyMapper userProxyMapper;


    @Override
    protected void additionalAuthenticationChecks(UserDetails userDetails, Authentication authentication) throws AuthenticationException {
		LoginUser loginUser = (LoginUser) userDetails;
		SysUserType sysUserType = SysUserType.selectType(loginUser.getUser().getUserType());
		switch (sysUserType) {
			case PROXY:
				Long status = tiktokProxyService.selectProxyStatus(loginUser.getUser().getUserId());
				if (status==null || !status.equals(0L)){
					throw new AuthoException("对不起，您属于的代理： 已停用");
				}
				break;
		}
        if (authentication.getCredentials() == null) {
            log.debug("账号密码为null");
            throw new BadCredentialsException("账号密码错误");
        } else {
            String presentedPassword = authentication.getCredentials().toString();
            if (!this.passwordEncoder.matches(presentedPassword, userDetails.getPassword())) {
               log.debug("密码错误");
                throw new BadCredentialsException("账号密码错误");
            }
        }
    }

    @Override
    protected Authentication createSuccessAuthentication(Authentication authentication, UserDetails user) {
		LoginUser loginUser = (LoginUser) user;
		String userType = loginUser.getUser().getUserType();
		SysUserType sysUserType = SysUserType.selectType(userType);
		TiktokUserShop tiktokUserShop;
		switch (sysUserType){
			case PROXY:
				TiktokUserProxy tiktokUserProxy = userProxyMapper.selectOne(Wrappers.lambdaQuery(TiktokUserProxy.class)
					.select(TiktokUserProxy::getProxyId)
					.eq(TiktokUserProxy::getUserId, loginUser.getUser().getUserId()));
				loginUser.setProxy(tiktokProxyService.queryById(tiktokUserProxy.getProxyId()));

				tiktokUserShop = userShopMapper.selectOne(Wrappers.lambdaQuery(TiktokUserShop.class)
					.select(TiktokUserShop::getShopId)
					.eq(TiktokUserShop::getUserId, loginUser.getUser().getUserId()));
				loginUser.setShop(tiktokShopService.queryById(tiktokUserShop.getShopId()));
				break;
			case SHOP:
				tiktokUserShop = userShopMapper.selectOne(Wrappers.lambdaQuery(TiktokUserShop.class)
					.select(TiktokUserShop::getShopId)
					.eq(TiktokUserShop::getUserId, loginUser.getUser().getUserId()));
				loginUser.setShop(tiktokShopService.queryById(tiktokUserShop.getShopId()));
				break;
		}

		AdminAuthenticationToken adminAuthenticationToken = new AdminAuthenticationToken(loginUser, authentication.getCredentials());
        adminAuthenticationToken.setDetails(authentication.getDetails());
        return adminAuthenticationToken ;
    }

    @Override
    protected App getAppInfo() {
        return null;
    }

    @Override
    protected UserDetails retrieveUser(String username, Authentication authentication) {
        AdminAuthenticationToken  adminAuthenticationToken= (AdminAuthenticationToken) authentication;
		boolean captchaOnOff = configService.selectCaptchaOnOff();
		// 验证码开关
		if (captchaOnOff) {
			String uuid = adminAuthenticationToken.getUuid();
			String verifyKey = Constants.CAPTCHA_CODE_KEY + uuid;
			String captcha = redisCache.getCacheObject(verifyKey);
			redisCache.deleteObject(verifyKey);
			if (captcha == null) {
				asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.expire"), ServletUtils.getRequest());
				throw new CaptchaExpireException();
			}
			if (!adminAuthenticationToken.getCode().equalsIgnoreCase(captcha)) {
				asyncService.recordLogininfor(username, Constants.LOGIN_FAIL, MessageUtils.message("user.jcaptcha.error"), ServletUtils.getRequest());
				throw new CaptchaAuthoException(500, "验证码错误");
			}
		}
        // 用户验证
        UserDetails userDetails = userDetailsService.loadUserByUsername(username);

        return userDetails;
    }

    @Override
    public boolean supports(Class<?> aClass) {
        return AdminAuthenticationToken.class.isAssignableFrom(aClass);
    }
}
